home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / p_hud.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  12.8 KB  |  545 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. #include "g_local.h"
  21.  
  22.  
  23.  
  24. /*
  25. ======================================================================
  26.  
  27. INTERMISSION
  28.  
  29. ======================================================================
  30. */
  31.  
  32. void MoveClientToIntermission (edict_t *ent)
  33. {
  34.     if (deathmatch->value || coop->value)
  35.         ent->client->showscores = true;
  36.     VectorCopy (level.intermission_origin, ent->s.origin);
  37.     ent->client->ps.pmove.origin[0] = level.intermission_origin[0]*8;
  38.     ent->client->ps.pmove.origin[1] = level.intermission_origin[1]*8;
  39.     ent->client->ps.pmove.origin[2] = level.intermission_origin[2]*8;
  40.     VectorCopy (level.intermission_angle, ent->client->ps.viewangles);
  41.     ent->client->ps.pmove.pm_type = PM_FREEZE;
  42.     ent->client->ps.gunindex = 0;
  43.     ent->client->ps.blend[3] = 0;
  44.     ent->client->ps.rdflags &= ~RDF_UNDERWATER;
  45.  
  46.     // clean up powerup info
  47.     ent->client->quad_framenum = 0;
  48.     ent->client->invincible_framenum = 0;
  49.     ent->client->breather_framenum = 0;
  50.     ent->client->enviro_framenum = 0;
  51.     ent->client->grenade_blew_up = false;
  52.     ent->client->grenade_time = 0;
  53.  
  54.     ent->viewheight = 0;
  55.     ent->s.modelindex = 0;
  56.     ent->s.modelindex2 = 0;
  57.     ent->s.modelindex3 = 0;
  58.     ent->s.modelindex = 0;
  59.     ent->s.effects = 0;
  60.     ent->s.sound = 0;
  61.     ent->solid = SOLID_NOT;
  62.  
  63.     // add the layout
  64.  
  65.     if (deathmatch->value || coop->value)
  66.     {
  67.         DeathmatchScoreboardMessage (ent, NULL);
  68.         gi.unicast (ent, true);
  69.     }
  70.  
  71. }
  72.  
  73. void BeginIntermission (edict_t *targ)
  74. {
  75.     int        i, n;
  76.     edict_t    *ent, *client;
  77.  
  78.     if (level.intermissiontime)
  79.         return;        // allready activated
  80.  
  81. //ZOID
  82.     if (deathmatch->value && ctf->value)
  83.         CTFCalcScores();
  84. //ZOID
  85.  
  86.     game.autosaved = false;
  87.  
  88.     // respawn any dead clients
  89.     for (i=0 ; i<maxclients->value ; i++)
  90.     {
  91.         client = g_edicts + 1 + i;
  92.         if (!client->inuse)
  93.             continue;
  94.         if (client->health <= 0)
  95.             respawn(client);
  96.     }
  97.  
  98.     level.intermissiontime = level.time;
  99.     level.changemap = targ->map;
  100.  
  101.     if (strstr(level.changemap, "*"))
  102.     {
  103.         if (coop->value)
  104.         {
  105.             for (i=0 ; i<maxclients->value ; i++)
  106.             {
  107.                 client = g_edicts + 1 + i;
  108.                 if (!client->inuse)
  109.                     continue;
  110.                 // strip players of all keys between units
  111.                 for (n = 0; n < MAX_ITEMS; n++)
  112.                 {
  113.                     if (itemlist[n].flags & IT_KEY)
  114.                         client->client->pers.inventory[n] = 0;
  115.                 }
  116.             }
  117.         }
  118.     }
  119.     else
  120.     {
  121.         if (!deathmatch->value)
  122.         {
  123.             level.exitintermission = 1;        // go immediately to the next level
  124.             return;
  125.         }
  126.     }
  127.  
  128.     level.exitintermission = 0;
  129.  
  130.     // find an intermission spot
  131.     ent = G_Find (NULL, FOFS(classname), "info_player_intermission");
  132.     if (!ent)
  133.     {    // the map creator forgot to put in an intermission point...
  134.         ent = G_Find (NULL, FOFS(classname), "info_player_start");
  135.         if (!ent)
  136.             ent = G_Find (NULL, FOFS(classname), "info_player_deathmatch");
  137.     }
  138.     else
  139.     {    // chose one of four spots
  140.         i = rand() & 3;
  141.         while (i--)
  142.         {
  143.             ent = G_Find (ent, FOFS(classname), "info_player_intermission");
  144.             if (!ent)    // wrap around the list
  145.                 ent = G_Find (ent, FOFS(classname), "info_player_intermission");
  146.         }
  147.     }
  148.  
  149.     VectorCopy (ent->s.origin, level.intermission_origin);
  150.     VectorCopy (ent->s.angles, level.intermission_angle);
  151.  
  152.     // move all clients to the intermission point
  153.     for (i=0 ; i<maxclients->value ; i++)
  154.     {
  155.         client = g_edicts + 1 + i;
  156.         if (!client->inuse)
  157.             continue;
  158.         MoveClientToIntermission (client);
  159.     }
  160. }
  161.  
  162.  
  163. /*
  164. ==================
  165. DeathmatchScoreboardMessage
  166.  
  167. ==================
  168. */
  169. void DeathmatchScoreboardMessage (edict_t *ent, edict_t *killer)
  170. {
  171.     char    entry[1024];
  172.     char    string[1400];
  173.     int        stringlength;
  174.     int        i, j, k;
  175.     int        sorted[MAX_CLIENTS];
  176.     int        sortedscores[MAX_CLIENTS];
  177.     int        score, total;
  178.     int        picnum;
  179.     int        x, y;
  180.     gclient_t    *cl;
  181.     edict_t        *cl_ent;
  182.     char    *tag;
  183.  
  184. //ZOID
  185.     if (ctf->value) {
  186.         CTFScoreboardMessage (ent, killer);
  187.         return;
  188.     }
  189. //ZOID
  190.  
  191.     // sort the clients by score
  192.     total = 0;
  193.     for (i=0 ; i<game.maxclients ; i++)
  194.     {
  195.         cl_ent = g_edicts + 1 + i;
  196.         if (!cl_ent->inuse)
  197.             continue;
  198.         score = game.clients[i].resp.score;
  199.         for (j=0 ; j<total ; j++)
  200.         {
  201.             if (score > sortedscores[j])
  202.                 break;
  203.         }
  204.         for (k=total ; k>j ; k--)
  205.         {
  206.             sorted[k] = sorted[k-1];
  207.             sortedscores[k] = sortedscores[k-1];
  208.         }
  209.         sorted[j] = i;
  210.         sortedscores[j] = score;
  211.         total++;
  212.     }
  213.  
  214.     // print level name and exit rules
  215.     string[0] = 0;
  216.  
  217.     stringlength = strlen(string);
  218.  
  219.     // add the clients in sorted order
  220.     if (total > 12)
  221.         total = 12;
  222.  
  223.     for (i=0 ; i<total ; i++)
  224.     {
  225.         cl = &game.clients[sorted[i]];
  226.         cl_ent = g_edicts + 1 + sorted[i];
  227.  
  228.         picnum = gi.imageindex ("i_fixme");
  229.         x = (i>=6) ? 160 : 0;
  230.         y = 32 + 32 * (i%6);
  231.  
  232.         // add a dogtag
  233.         if (cl_ent == ent)
  234.             tag = "tag1";
  235.         else if (cl_ent == killer)
  236.             tag = "tag2";
  237.         else
  238.             tag = NULL;
  239.         if (tag)
  240.         {
  241.             Com_sprintf (entry, sizeof(entry),
  242.                 "xv %i yv %i picn %s ",x+32, y, tag);
  243.             j = strlen(entry);
  244.             if (stringlength + j > 1024)
  245.                 break;
  246.             strcpy (string + stringlength, entry);
  247.             stringlength += j;
  248.         }
  249.  
  250.         // send the layout
  251.         Com_sprintf (entry, sizeof(entry),
  252.             "client %i %i %i %i %i %i ",
  253.             x, y, sorted[i], cl->resp.score, cl->ping, (level.framenum - cl->resp.enterframe)/600);
  254.         j = strlen(entry);
  255.         if (stringlength + j > 1024)
  256.             break;
  257.         strcpy (string + stringlength, entry);
  258.         stringlength += j;
  259.     }
  260.  
  261.     gi.WriteByte (svc_layout);
  262.     gi.WriteString (string);
  263. }
  264.  
  265.  
  266. /*
  267. ==================
  268. DeathmatchScoreboard
  269.  
  270. Draw instead of help message.
  271. Note that it isn't that hard to overflow the 1400 byte message limit!
  272. ==================
  273. */
  274. void DeathmatchScoreboard (edict_t *ent)
  275. {
  276.     DeathmatchScoreboardMessage (ent, ent->enemy);
  277.     gi.unicast (ent, true);
  278. }
  279.  
  280.  
  281. /*
  282. ==================
  283. Cmd_Score_f
  284.  
  285. Display the scoreboard
  286. ==================
  287. */
  288. void Cmd_Score_f (edict_t *ent)
  289. {
  290.     ent->client->showinventory = false;
  291.     ent->client->showhelp = false;
  292. //ZOID
  293.     if (ent->client->menu)
  294.         PMenu_Close(ent);
  295. //ZOID
  296.  
  297.     if (!deathmatch->value && !coop->value)
  298.         return;
  299.  
  300.     if (ent->client->showscores)
  301.     {
  302.         ent->client->showscores = false;
  303.         ent->client->update_chase = true;
  304.         return;
  305.     }
  306.  
  307.     ent->client->showscores = true;
  308.  
  309.     DeathmatchScoreboard (ent);
  310. }
  311.  
  312.  
  313. /*
  314. ==================
  315. HelpComputer
  316.  
  317. Draw help computer.
  318. ==================
  319. */
  320. void HelpComputer (edict_t *ent)
  321. {
  322.     char    string[1024];
  323.     char    *sk;
  324.  
  325.     if (skill->value == 0)
  326.         sk = "easy";
  327.     else if (skill->value == 1)
  328.         sk = "medium";
  329.     else if (skill->value == 2)
  330.         sk = "hard";
  331.     else
  332.         sk = "hard+";
  333.  
  334.     // send the layout
  335.     Com_sprintf (string, sizeof(string),
  336.         "xv 32 yv 8 picn help "            // background
  337.         "xv 202 yv 12 string2 \"%s\" "        // skill
  338.         "xv 0 yv 24 cstring2 \"%s\" "        // level name
  339.         "xv 0 yv 54 cstring2 \"%s\" "        // help 1
  340.         "xv 0 yv 110 cstring2 \"%s\" "        // help 2
  341.         "xv 50 yv 164 string2 \" kills     goals    secrets\" "
  342.         "xv 50 yv 172 string2 \"%3i/%3i     %i/%i       %i/%i\" ", 
  343.         sk,
  344.         level.level_name,
  345.         game.helpmessage1,
  346.         game.helpmessage2,
  347.         level.killed_monsters, level.total_monsters, 
  348.         level.found_goals, level.total_goals,
  349.         level.found_secrets, level.total_secrets);
  350.  
  351.     gi.WriteByte (svc_layout);
  352.     gi.WriteString (string);
  353.     gi.unicast (ent, true);
  354. }
  355.  
  356.  
  357. /*
  358. ==================
  359. Cmd_Help_f
  360.  
  361. Display the current help message
  362. ==================
  363. */
  364. void Cmd_Help_f (edict_t *ent)
  365. {
  366.     // this is for backwards compatability
  367.     if (deathmatch->value)
  368.     {
  369.         Cmd_Score_f (ent);
  370.         return;
  371.     }
  372.  
  373.     ent->client->showinventory = false;
  374.     ent->client->showscores = false;
  375.  
  376.     if (ent->client->showhelp && (ent->client->resp.game_helpchanged == game.helpchanged))
  377.     {
  378.         ent->client->showhelp = false;
  379.         return;
  380.     }
  381.  
  382.     ent->client->showhelp = true;
  383.     ent->client->resp.helpchanged = 0;
  384.     HelpComputer (ent);
  385. }
  386.  
  387.  
  388. //=======================================================================
  389.  
  390. /*
  391. ===============
  392. G_SetStats
  393. ===============
  394. */
  395. void G_SetStats (edict_t *ent)
  396. {
  397.     gitem_t        *item;
  398.     int            index, cells;
  399.     int            power_armor_type;
  400.  
  401.     //
  402.     // health
  403.     //
  404.     ent->client->ps.stats[STAT_HEALTH_ICON] = level.pic_health;
  405.     ent->client->ps.stats[STAT_HEALTH] = ent->health;
  406.  
  407.     //
  408.     // ammo
  409.     //
  410.     if (!ent->client->ammo_index /* || !ent->client->pers.inventory[ent->client->ammo_index] */)
  411.     {
  412.         ent->client->ps.stats[STAT_AMMO_ICON] = 0;
  413.         ent->client->ps.stats[STAT_AMMO] = 0;
  414.     }
  415.     else
  416.     {
  417.         item = &itemlist[ent->client->ammo_index];
  418.         ent->client->ps.stats[STAT_AMMO_ICON] = gi.imageindex (item->icon);
  419.         ent->client->ps.stats[STAT_AMMO] = ent->client->pers.inventory[ent->client->ammo_index];
  420.     }
  421.     
  422.     //
  423.     // armor
  424.     //
  425.     power_armor_type = PowerArmorType (ent);
  426.     if (power_armor_type)
  427.     {
  428.         cells = ent->client->pers.inventory[ITEM_INDEX(FindItem ("cells"))];
  429.         if (cells == 0)
  430.         {    // ran out of cells for power armor
  431.             ent->flags &= ~FL_POWER_ARMOR;
  432.             gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
  433.             power_armor_type = 0;;
  434.         }
  435.     }
  436.  
  437.     index = ArmorIndex (ent);
  438.     if (power_armor_type && (!index || (level.framenum & 8) ) )
  439.     {    // flash between power armor and other armor icon
  440.         ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex ("i_powershield");
  441.         ent->client->ps.stats[STAT_ARMOR] = cells;
  442.     }
  443.     else if (index)
  444.     {
  445.         item = GetItemByIndex (index);
  446.         ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex (item->icon);
  447.         ent->client->ps.stats[STAT_ARMOR] = ent->client->pers.inventory[index];
  448.     }
  449.     else
  450.     {
  451.         ent->client->ps.stats[STAT_ARMOR_ICON] = 0;
  452.         ent->client->ps.stats[STAT_ARMOR] = 0;
  453.     }
  454.  
  455.     //
  456.     // pickup message
  457.     //
  458.     if (level.time > ent->client->pickup_msg_time)
  459.     {
  460.         ent->client->ps.stats[STAT_PICKUP_ICON] = 0;
  461.         ent->client->ps.stats[STAT_PICKUP_STRING] = 0;
  462.     }
  463.  
  464.     //
  465.     // timers
  466.     //
  467.     if (ent->client->quad_framenum > level.framenum)
  468.     {
  469.         ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_quad");
  470.         ent->client->ps.stats[STAT_TIMER] = (ent->client->quad_framenum - level.framenum)/10;
  471.     }
  472.     else if (ent->client->invincible_framenum > level.framenum)
  473.     {
  474.         ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_invulnerability");
  475.         ent->client->ps.stats[STAT_TIMER] = (ent->client->invincible_framenum - level.framenum)/10;
  476.     }
  477.     else if (ent->client->enviro_framenum > level.framenum)
  478.     {
  479.         ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_envirosuit");
  480.         ent->client->ps.stats[STAT_TIMER] = (ent->client->enviro_framenum - level.framenum)/10;
  481.     }
  482.     else if (ent->client->breather_framenum > level.framenum)
  483.     {
  484.         ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_rebreather");
  485.         ent->client->ps.stats[STAT_TIMER] = (ent->client->breather_framenum - level.framenum)/10;
  486.     }
  487.     else
  488.     {
  489.         ent->client->ps.stats[STAT_TIMER_ICON] = 0;
  490.         ent->client->ps.stats[STAT_TIMER] = 0;
  491.     }
  492.  
  493.     //
  494.     // selected item
  495.     //
  496.     if (ent->client->pers.selected_item == -1)
  497.         ent->client->ps.stats[STAT_SELECTED_ICON] = 0;
  498.     else
  499.         ent->client->ps.stats[STAT_SELECTED_ICON] = gi.imageindex (itemlist[ent->client->pers.selected_item].icon);
  500.  
  501.     ent->client->ps.stats[STAT_SELECTED_ITEM] = ent->client->pers.selected_item;
  502.  
  503.     //
  504.     // layouts
  505.     //
  506.     ent->client->ps.stats[STAT_LAYOUTS] = 0;
  507.  
  508.     if (deathmatch->value)
  509.     {
  510.         if (ent->client->pers.health <= 0 || level.intermissiontime
  511.             || ent->client->showscores)
  512.             ent->client->ps.stats[STAT_LAYOUTS] |= 1;
  513.         if (ent->client->showinventory && ent->client->pers.health > 0)
  514.             ent->client->ps.stats[STAT_LAYOUTS] |= 2;
  515.     }
  516.     else
  517.     {
  518.         if (ent->client->showscores || ent->client->showhelp)
  519.             ent->client->ps.stats[STAT_LAYOUTS] |= 1;
  520.         if (ent->client->showinventory && ent->client->pers.health > 0)
  521.             ent->client->ps.stats[STAT_LAYOUTS] |= 2;
  522.     }
  523.  
  524.     //
  525.     // frags
  526.     //
  527.     ent->client->ps.stats[STAT_FRAGS] = ent->client->resp.score;
  528.  
  529.     //
  530.     // help icon / current weapon if not shown
  531.     //
  532.     if (ent->client->resp.helpchanged && (level.framenum&8) )
  533.         ent->client->ps.stats[STAT_HELPICON] = gi.imageindex ("i_help");
  534.     else if ( (ent->client->pers.hand == CENTER_HANDED || ent->client->ps.fov > 91)
  535.         && ent->client->pers.weapon)
  536.         ent->client->ps.stats[STAT_HELPICON] = gi.imageindex (ent->client->pers.weapon->icon);
  537.     else
  538.         ent->client->ps.stats[STAT_HELPICON] = 0;
  539.  
  540. //ZOID
  541.     SetCTFStats(ent);
  542. //ZOID
  543. }
  544.  
  545.